import oscP5.*;
import netP5.*;

import codeanticode.gsvideo.*;


GSCapture cam;
FrameDiff frameDiff;
MotiongramX motiongramX;
MotiongramY motiongramY;
Stat splitX, splitY;
Gesture gesture;
OscP5 oscP5;
NetAddress myRemoteLocation;
int w, h, motionT, minMotion;
float leftX, leftY, rightX, rightY, motionW, motionV, prebang;

void setup() {
  // PARAMETERS
  w = 320;
  h = 240;
  motionT = 60;
  minMotion = 800;
  motionW = 0.5;
  
  oscP5 = new OscP5(this,8000);
  myRemoteLocation = new NetAddress ("localhost", 8001);
  size(2*w, 2*h);
  frameRate(25);
  cam = new GSCapture(this, w, h);
  frameDiff = new FrameDiff(w, h, motionT);
  motiongramX = new MotiongramX(w, h);
  motiongramY = new MotiongramY(w, h);
  splitX = new SplitStat(w/2); //new OtsuStat();
  splitY = new SplitStat(h);
  gesture = new Gesture();
  // calcolo il complementare di motionW una volta per tutte
  motionV = 1 - motionW;
  cam.start();
}

void draw() {
  if (cam.available() == true) {
    // PROCESSING PART
    cam.read();
    PImage diff = frameDiff.process(cam);
    float[] movX = motiongramX.process(diff);
    splitX.process(movX);
    int thresh = splitX.getThresh();
    float[] movY = motiongramY.process(diff, splitX.getThresh());
    splitY.process(movY);
    // AGGIUNTA SOGLIA DI MOVIMENTO MINIMO
    // se il semiquadro è troppo fermo la posizione non viene aggiornata
    // AGGIUNTA MEDIA ESPONENZIALE SU AGGIORNAMENTO POSIZIONE
    // riduce la rumorosità dei dati e quindi i falsi positivi
    if (splitY.getWeightL() > minMotion) {
      leftX = leftX * motionV + splitX.getMeanL() * motionW;
      leftY = leftY * motionV + splitY.getMeanL() * motionW;
    }
    if (splitY.getWeightR() > minMotion) {
      rightX = rightX * motionV + splitX.getMeanR() * motionW;
      rightY = rightY * motionV + (splitY.getMeanR() - h) * motionW;
    }
    // bang == 0 : nessun beat
    // bang > 0  : battere
    // bang < 0  : levare
    float bang = gesture.process(leftX, leftY, rightX, rightY, minMotion, splitY.getWeightR());
    if (bang > 0) 
    {
      
      System.out.println(bang);        // === OSC CODE GOES HERE ===ù
      OscMessage banged = new OscMessage("/beat");
      banged.add("bang");
      OscMessage volume = new OscMessage("/vol");
      volume.add(bang);
      oscP5.send(banged, myRemoteLocation);
      oscP5.send(volume, myRemoteLocation);
    }
    
    // OUTPUT ON SCREEN
    image(diff, 0, h);
    motiongramX.setMarks(thresh, leftX, rightX);
    motiongramX.display(0, 0);
    motiongramY.setMarks(leftY, rightY);
    motiongramY.displayL(w, 0);
    motiongramY.displayR(w, h);
    pushMatrix();
    translate(0, h);
    // punto grosso dopo un battere, punto piccolo dopo un levare
    if (bang > 0) strokeWeight(50);
    if (bang < 0) strokeWeight(10);
    stroke(255, 0, 0);
    point(leftX, leftY);
    stroke(0, 0, 255);
    point(rightX, rightY);
    popMatrix();
  }
}


